package com.ww.springboot.boot.thread.threadlocal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 描述：
 *
 * @author 🧑 ‍wanwei
 * @since 2022-04-13 08:59
 */
public class ThreadLocalDemo内存泄露2 {


    /**
     * 即使threadLocalMap 的key是弱引用 但是 方法栈对threadLocal的引用是强引用 因此GC不会回收threadLocal
     *
     * 除非手动置为null,这时强引用消失 弱引用也会被GC掉 threadLocalMap对value就没任何办法了 既不能使用 又不能回收
     *
     * key即使设置为强引用,threadLocal一旦设置为null,什么引用都无效;
     * 反而设置为弱引用可以避免大多数情况下的内存泄露:线程被回收 但是threadLocal没有被置为null 这时也应该被GC
     *
     */
    private static ThreadLocal<byte[]> threadLocal = new ThreadLocal();

    //只开一个线程 线程肯定会被复用
    //模拟线程被回收时 threadLocalMap里面的数据是否会被回收
    private static final ExecutorService executorService = new ThreadPoolExecutor(1,10,1,
            TimeUnit.SECONDS, new LinkedBlockingQueue());


    /**
     * 内存泄露模拟
     *
     * 除非在多线程的情况下,复用线程,且不回收线程, 但是后续又不对threadLocal做任何操作 这样就会导致线程依旧存在 但是实际不会再对值做处理
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {

        Thread.sleep(20000);
        for (int i = 0; i < 11; i++) {
            executorService.submit(()->{
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //System.out.println(Thread.currentThread());
                threadLocal.set(new byte[1024*1024*64]);
                System.out.println(threadLocal.get());
            });
        }
        Thread.sleep(10000);
        System.out.println("结束第一次休眠");
        //线程复用
        for (int i = 0; i < 10; i++) {
            Thread.sleep(10000);
            System.gc();
//            executorService.submit(()->{
//                System.gc();
//                System.out.println("------------GC------------");
//                //System.out.println(threadLocal.get());
//                //threadLocal.remove();
//            });
        }

        System.out.println();
    }
}
